﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using Slaks.Graphs.GraphBuilder;

namespace Slaks.Graphs.Algorithms
{    
	/// <summary>
	/// Base class for measuring distances between two graphs. 
	/// </summary>
    public class GraphDistanceBase : IGraphDistance
    {
        protected Dictionary<String, Dictionary<Object, Object>> _properties;
        protected Graph one;
        protected Graph two;
        public const String DistanceAlgorithmParam = "DistanceAlgorithm";
		

		#region Constructor
		public GraphDistanceBase()
        {
			IsVisible = true;
            _properties = new Dictionary<string, Dictionary<object, object>>();
        }

        public GraphDistanceBase(Graph one, Graph two) : this ()
        {
            this.one = one;
            this.two = two;           
        }
		#endregion
		
        #region IGraphDistance Members
		/// <summary>
		/// Gets the distance between to graph according to the current implementation. 
		/// </summary>
		/// <returns>
		/// The distance measure between the two given graphs.
		/// </returns>
        public virtual double GetDistance()
        {
            throw new NotImplementedException();
        }
        #endregion

        #region IGraphDistance Members        

        public virtual String GetName()
        {
            return GetType().Name;
		}

        public Graph firstGraph
        {
            get
            {
                return one;
            }
            set
            {
                one = value;
            }
        }

        public Graph secondGraph
        {
            get
            {
                return two;
            }
            set
            {
                two = value;
            }
        }
		/// <summary>
		/// Creates a shallow copy of the current instance 
		/// </summary>
		/// <returns>
		/// A shallow copy of the current instance
		/// </returns>
        public GraphDistanceBase clone()
        {
            ConstructorInfo ci = this.GetType().GetConstructor(new Type[] { });
            return (GraphDistanceBase)ci.Invoke( new Object[] { });
        }     
		/// <summary>
		/// Test to see if this distance measure can be used for the given graph 
		/// </summary>
		/// <param name="graph">
		/// A reference to the graph <see cref="Graph"/> you'd like to measure the distance to
		/// </param>
		/// <returns>
		/// If <c>true</c> - the graph is applicable for this kind of distance measure
		/// </returns>
        public bool CanOperateOnRepresentation (IRepresentation GB)
        {
            return CanOperateOnRepresentation(GB.getBuilderType());
        }
		public bool CanOperateOnRepresentation(Graph graph)
		{
			return CanOperateOnRepresentation(graph.GraphBuilderType);
		}
        public virtual bool CanOperateOnRepresentation(BuilderType builderType)
        {
            
		
			switch(builderType)
			{
				case BuilderType.StandardRepresentationSchenker:
                case BuilderType.ExtractorBuilderNodesOnly:
                case BuilderType.StandardRepresentationSlaks:
                case BuilderType.SimpleRepresentationSchenker:
                case BuilderType.SimpleRepresentationSlaks:
                case BuilderType.NDistanceRepresentationSchenker:
                case BuilderType.NDistanceRepresentationSlaks:
                case BuilderType.NSimpleDistanceRepresentationSchenker:
                case BuilderType.NSimpleDistanceRepresentationSlaks:
				return true;
			}
			return false;
		          
        }
        protected bool isRepresentationContainedInList ( IRepresentation GB, List<IRepresentation> representations )
        {
			foreach(IRepresentation representation in representations)
            {
                if ( GB.getBuilderType () == representation.getBuilderType())
                    return true;
            }
            return false;
        }
		public virtual bool IsVisible {get;protected set;}
			
        #endregion
		public static IEnumerable<T> GetAvailableDistAlgorithms<T>() where T:GraphDistanceBase
		{
			IList<T> result = new List<T>();
			var assemblies = AppDomain.CurrentDomain.GetAssemblies();
			foreach (Assembly assembly in assemblies) {
				if(assembly.FullName.Contains("mscorlib")) continue;
				var types = assembly.GetTypes();
				foreach (Type type in types) {
					if (type.IsClass && type.IsSubclassOf(typeof(T)))
					{
						ConstructorInfo ci = type.GetConstructor(new Type[] { });
						T alg = (T)ci.Invoke(new object[]{});
						result.Add(alg);
						
					}
				}
			}
			return result;
		}
    }
}
